import {equalsTo} from "../core/Obj";
import Map, {Entry} from "../map/Map";
import Set from "../set/Set";
import Collection from "../core/Collection";
import IllegalArgumentException from "../exceptions/IllegalArgumentException";
import FullCapacityException from "../exceptions/FullCapacityException";

/**
 * 一些针对{@link Map}的静态方法。
 *
 * @version 1.0
 */
export default class Maps {

  /**
   * 通过依次对两个映射进行比较，判断这两个映射是否相等。
   *
   * 如果两个映射长度相等，则进行依次比较。否则直接判定为不相等。
   *
   * @param a 第一个映射
   * @param b 第二个映射
   * @return {boolean} 两个映射是否相等
   * @version 1.0
   */
  public static equals<K, V>(a: Map<K, V>, b: Map<K, V>): boolean {
    if (a.size() !== b.size()) {
      return false;
    } else {
      let flag = true;
      const iteratorA = a.entrySet().iterator();
      const iteratorB = b.entrySet().iterator();
      let elementA: IteratorResult<Entry<K, V>>;
      let elementB: IteratorResult<Entry<K, V>>;
      do {
        elementA = iteratorA.next();
        elementB = iteratorB.next();
        if (!equalsTo(elementA.value, elementB.value)) {
          flag = false;
          break;
        }
      } while (elementA.done || elementB.done);
      return flag;
    }
  }

  /**
   * 由一个不重复的集合作为键，一个可重复的集合作为值，将其存入指定映射中。
   *
   * @param origin 需要存入元素的映射
   * @param keySet 由不重复元素构成的键集合
   * @param valueCollection 由可重复元素构成的值集合
   * @throws {FullCapacityException} 如果此映射已经无法容纳更多的键值对
   * @throws {IllegalArgumentException} 如果键集合的长度于值集合的长度不等
   * @throws {UnsupportedOperationException} put方法不被此映射支持
   */
  public static zip<K, V>(origin: Map<K, V>, keySet: Set<K>, valueCollection: Collection<V>): void {
    if (keySet.size() !== valueCollection.size()) {
      throw new IllegalArgumentException("keySet should have a same size to valueCollection");
    } else if (keySet.size() + origin.size() > origin.capacity()) {
      throw new FullCapacityException("map", origin.capacity());
    }
    else {
      const keySetIterator = keySet.iterator();
      const valueCollectionIterator = valueCollection.iterator();
      let keyElement: IteratorResult<K>;
      let valueElement: IteratorResult<V>;
      do {
        keyElement = keySetIterator.next();
        valueElement = valueCollectionIterator.next();
        origin.put(keyElement.value, valueElement.value);
      } while (keyElement.done || valueElement.done);
    }
  }
}
